package org.school.streaming.net.client.packets;

/**
 * @authors Jeffrey Goudzwaard,
 * 			Davin Terrizzi
 * @version	1.0
 * @date	18-4-2013
 */

/**
 * Class representing an RTP network packet
 * @author Davin
 *
 */
public class RTPPacket
{
	private static int HEADER_SIZE = 12;
	
	private int version;
	private int padding;
	private int extension;
	private int cc;
	private int marker;
	private int payloadType;
	private int sequenceNumber;
	private int timeStamp;
	private int ssrc;
	private int payloadSize;
	
	private byte[] header;
	private byte[] payload;
	
	/**
	 * Constructor
	 * Initializes first RTP packet with some needed values
	 * @param pType Integer representing type of payload
	 * @param frameNr Integer representing current frame no.
	 * @param time Integer representing current timestamp
	 * @param data Byte array representing payload data
	 * @param dataLength Integer representing length of payload data
	 */
	public RTPPacket( int pType, int frameNr, int time, byte[] data, int dataLength )
	{
		// Some header values are not used
		version = 2;
		padding = 0;
		extension = 0;
		cc = 0;
		marker = 0;
		ssrc = 0;
		
		sequenceNumber = frameNr;
		timeStamp = time;
		payloadType = pType;
		
		header = new byte[ HEADER_SIZE ];
		header[0] = ( byte ) ( version << 6 );
		header[0] = ( byte ) ( header[0] | padding << 5 );
		header[0] = ( byte ) ( header[0] | extension << 4 );
		header[0] = ( byte ) ( header[0] | cc );
		header[1] = ( byte ) ( header[1] | marker << 7 );
		header[1] = ( byte ) ( header[1] | pType );
		header[2] = ( ( byte ) ( sequenceNumber >> 8 ) );
		header[3] = ( ( byte ) ( sequenceNumber & 0xFF ) );
		header[4] = ( ( byte ) ( time >> 24 ) );
		header[5] = ( ( byte ) ( time >> 16) );
		header[6] = ( ( byte ) ( time >> 8 ) );
		header[7] = ( ( byte ) ( time & 0xFF ) );
		header[8] = ( ( byte ) ( ssrc >> 24 ) );
		header[9] = ( ( byte ) ( ssrc >> 16 ) );
		header[10] = ( ( byte ) ( ssrc >> 8 ) );
		header[11] = ( ( byte ) ( ssrc & 0xFF ) );
		
		payloadSize = dataLength;
		
		// Iterate through payload parameter to set instance payload  
		payload = new byte[ dataLength ];
		for( int i = 0; i < dataLength; i++ )
		{
			payload[i] = data[i];
		}
		
	}
	
	/**
	 * Constructor
	 * Initializes new sequential RTP packet from existing prior packet
	 * @param packet Byte-array representing prior RTP packet 
	 * @param length Integer representing total length of packet
	 */
	public RTPPacket( byte[] packet, int length )
	{
		
		// Some header values are not used
		version = 2;
		padding = 0;
		extension = 0;
		cc = 0;
		marker = 0;
		ssrc = 0;
		
		if( length >= HEADER_SIZE )
		{
			header = new byte[ HEADER_SIZE ];
			for( int i = 0; i < HEADER_SIZE; i++ )
			{
				header[i] = packet[i];
			}
			
			// Set new payload size and payload data
			payloadSize = length - HEADER_SIZE;
			payload = new byte[ payloadSize ];
			
			for( int i = HEADER_SIZE; i < length; i++ )
			{
				payload[ i - HEADER_SIZE ] = packet[i];
			}
			
			payloadType = header[1] & 127;
			sequenceNumber = unsigned_int( header[3] ) + 256 * unsigned_int( header[2] );
			timeStamp = unsigned_int( header[7] ) + 256 * unsigned_int( header[6] ) + 65536 * unsigned_int( header[5] ) + 16777216 * unsigned_int( header[4] );
		}
	}
	
	/**
	 * Logs packet header to standard output
	 */
	public void printHeader()
	{
		for( int i = 0; i< ( HEADER_SIZE - 4 ); i++ )
		{
			for( int j = 7; j >= 0; j-- )
			{
				if( ( ( 1 << j ) & header[i] ) != 0 )
				{
					//System.out.println( "1" );
				}
				else
				{
					//System.out.println( "0" );
				}
			}
		}
	}

	public int getSequenceNumber()
	{
		return sequenceNumber;
	}

	public int getTimeStamp()
	{
		return timeStamp;
	}

	public int getPayloadType()
	{
		return payloadType;
	}
	
	public int getVersion()
	{
		return version;
	}
	
	public int getPadding()
	{
		return padding;
	}
	
	public int getExtension()
	{
		return extension;
	}
	
	public int getCC()
	{
		return cc;
	}
	
	public int getMarker()
	{
		return marker;
	}
	
	public int getSSRC()
	{
		return ssrc;
	}



	public int getPayloadLength()
	{
		return payloadSize;
	}

	public int getPayload( byte[] data )
	{
		for( int i = 0; i < payloadSize; i++ )
		{
			data[i] = payload[i];
		}
		
		return payloadSize;
	}
	
	public int getLength()
	{
		return payloadSize + HEADER_SIZE;
	}
	
	public int getPacket( byte[] packet )
	{
		for( int i = 0; i < HEADER_SIZE; i++ )
		{
			packet[i] = header[i];
		}
		
		for( int i = 0; i < payloadSize; i++ )
		{
			packet[ i + HEADER_SIZE ] = payload[i];
		}
		
		return payloadSize + HEADER_SIZE;
	}
	
	/**
	 * Converts int to unsigned int
	 * @param nr Int to convert to u_int
	 * @return u_int representation of int nr.
	 */
	public static int unsigned_int( int nr )
	{
		if( nr >= 0 )
		{
			return nr;
		}
		else
		{
			return 256 + nr;
		}
	}
}
